package game.games.carcassonne;

import game.AbstractGame;
import game.AbstractRunnable;
import game.GraphicUtil;
import game.Position;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;

import javax.swing.SwingUtilities;

public class Carcassonne extends AbstractRunnable
{
    protected static final boolean OVERRIDE_ENABLED = true;
    
    private static Carcassonne     instance;
    
    public synchronized static Carcassonne getInstance()
    {
        if (instance == null)
        {
            synchronized (Carcassonne.class)
            {
                instance = new Carcassonne();
            }
        }
        return instance;
    }
    
    private Position       frameSize;
    private int            mouseOverIndex   = -1;
    private int            currentTileIndex = 0;
    private int            currentTileAngle = 0;
    
    private CarcassonneMap map;
    
    @Override
    public void render(Graphics g)
    {
        if (frameSize != null && map != null)
        {
            map.fillRect(g, 0, 0, frameSize.getWidth(), frameSize.getHeight(), Color.WHITE);
            for (int index = 0; index < map.getSize().getSum(); index++)
            {
                Position position = map.calculatePosition(index);
                Tile tile = map.getTile(index);
                BufferedImage img = null;
                if (tile != null && (index == mouseOverIndex && OVERRIDE_ENABLED) == false)
                {
                    img = tile.getBitmap();
                    int angle = map.getAngle(index);
                    if (angle != 0)
                    {
                        img = GraphicUtil.rotateImage(img, angle);
                    }
                }
                else
                {
                    if (index == mouseOverIndex)
                    {
                        img = TileLoader.getTile(currentTileIndex).getBitmap();
                        if (currentTileAngle != 0)
                        {
                            img = GraphicUtil.rotateImage(img, currentTileAngle);
                        }
                    }
                }
                if (img != null)
                {
                    map.drawImage(g, position.getX(), position.getY(), img);
                }
                else
                {
                    map.drawRect(g, position.getX(), position.getY(), Color.BLACK);
                }
            }
        }
    }
    
    @Override
    protected void doNext()
    {
    }
    
    @Override
    protected synchronized void reset()
    {
        frameSize = new Position(CarcassonneRunner.getInstance().getSize());
        if (map == null)
        {
            // size
            Position size = new Position(50, 50);
            map = new CarcassonneMap();
            map.setSize(size);
        }
        super.reset();
    }
    
    @Override
    public MouseListener getMouseControl()
    {
        return new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e)
            {
                if (isRunning())
                {
                    if (SwingUtilities.isRightMouseButton(e))
                    {
                        if (e.isControlDown())
                        {
                            currentTileIndex = 0;
                            currentTileAngle = 0;
                        }
                        else
                        {
                            currentTileAngle += 90;
                            if (currentTileAngle >= 360)
                            {
                                currentTileAngle = 0;
                            }
                        }
                    }
                    else if (SwingUtilities.isLeftMouseButton(e))
                    {
                        int index = map.calculateIndex(map.calcCoord(e.getPoint()));
                        if (OVERRIDE_ENABLED || map.getTile(index) == null)
                        {
                            map.setTile(index, TileLoader.getTile(currentTileIndex), currentTileAngle);
                        }
                    }
                }
            }
        };
    }
    
    @Override
    public MouseMotionListener getMouseMotionListener()
    {
        return new MouseMotionAdapter() {
            
            @Override
            public void mouseMoved(MouseEvent e)
            {
                if (isRunning())
                {
                    try
                    {
                        mouseOverIndex = map.calculateIndex(map.calcCoord(e.getPoint()));
                    }
                    catch (IndexOutOfBoundsException ex)
                    {
                        //
                    }
                }
            }
            
            @Override
            public void mouseDragged(MouseEvent e)
            {
                if (isRunning())
                {
                    try
                    {
                        mouseOverIndex = map.calculateIndex(map.calcCoord(e.getPoint()));
                    }
                    catch (IndexOutOfBoundsException ex)
                    {
                        //
                    }
                }
            }
        };
    }
    
    @Override
    public MouseWheelListener getMouseWheelListener()
    {
        return new MouseWheelListener() {
            
            @Override
            public void mouseWheelMoved(MouseWheelEvent e)
            {
                int rotation = e.getWheelRotation();
                int index = currentTileIndex + rotation;
                if (index < 0)
                {
                    index += TileLoader.sumTiles();
                }
                if (index >= TileLoader.sumTiles())
                {
                    index -= TileLoader.sumTiles();
                }
                currentTileIndex = index;
                currentTileAngle = 0;
            }
        };
    }
    
    public static class CarcassonneRunner extends AbstractGame
    {
        private static CarcassonneRunner instance;
        
        public synchronized static CarcassonneRunner getInstance()
        {
            synchronized (CarcassonneRunner.class)
            {
                if (instance == null)
                {
                    instance = new CarcassonneRunner();
                }
                return instance;
            }
        }
        
        protected CarcassonneRunner()
        {
            super(Carcassonne.getInstance());
        }
        
        public static void main(String[] args)
        {
            Thread t = new Thread(CarcassonneRunner.getInstance(), "Carcassonne");
            t.start();
        }
    }
}
